/* PhotoImport
 * Our main window
 * Copyright by faena.com
 * 2010-08-17 VM created
 * 
*/
using System;
using Gtk;
using System.Threading;

namespace PhotoImport
{
	public partial class MainWindow : Gtk.Window
	{
		//When source dir is set, update uxSourcedir
		public string SourceDir
		{
			set
			{
				uxSourceDir.SetFilename(value);
				
			}
		}
		
		private bool _busy = false; //true = downloading in progress, false = job not started or done
		
		/// <summary>
		/// Gracefully abort the thread before continuing
		/// </summary>
		private void NotBusyOrWait()
		{
			//only need to wait if the program is downloading
			if (_busy) 
			{
				_download.Abort (); //issue abort request
				
				//wait until not busy. 
				//TODO: consider adding a timeout for the while
				while(_busy)
					System.Threading.Thread.Sleep(100); //sleep UI thread 100 ms to yield
				
			}
		}
		
		//creates a DoDownload object, but do not run it yet
		private DoDownload _download = new DoDownload ();
		
		/// <summary>
		/// Our mian window is loaded
		/// </summary>
		public MainWindow () : base(Gtk.WindowType.Toplevel)
		{
			//Mono designer generated code
			Build (); 

			SettingFile sFile = new SettingFile();
			if (sFile.Reload ())
			{
				//load default source location
				uxSourceDir.SetFilename(sFile.SourceDir);
			}//if there is no setting file yet. uxSourceDir is left to the Mono.
			

			//Subscribe DoDownload events
			_download.LogEvent += HandleDownloadLogEvent;
			
			_download.ProgressUpdateEvent += HandleDownloadProgressUpdateEvent;
			
			_download.DownloadCompleteEvent += HandleDownloadCompleteEvent;
			
			_download.SendAlertEvent += Handle_SendAlertEvent;
		}

		void Handle_SendAlertEvent (string pMessage)
		{
			Gtk.Application.Invoke (delegate {
				MessageDialog box = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.Ok, pMessage);
				box.Run();
				box.Destroy();
			});
		}

		/// <summary>
		/// When download completed
		/// </summary>
		void HandleDownloadCompleteEvent ()
		{
			_busy = false;
			Gtk.Application.Invoke (delegate {
				//Hide the Stop button
				uxStop.Visible = false;		
				//Add a text on progress bar: Completed.
				uxProgress.Text += " Completed";
			});
			
		}

		/// <summary>
		/// When window closed by user
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="a">
		/// A <see cref="DeleteEventArgs"/>
		/// </param>
		protected void OnDeleteEvent (object sender, DeleteEventArgs a)
		{
			NotBusyOrWait();
			Application.Quit (); 
		}
		
		/// <summary>
		/// Show about window 
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="System.EventArgs"/>
		/// </param>
		protected virtual void OnAboutActionActivated (object sender, System.EventArgs e)
		{
			// Create a new About dialog
			AboutDialog about = new AboutDialog ();
			
			// Change the Dialog's properties to the appropriate values.
			about.ProgramName = "Photo Import";
			Version ver = new Version(System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
			about.Version = ver.Major + "." + ver.Minor;
			
			
			about.Copyright = "Copyright by faena.com. Build " + ver.ToString();
			
			about.Website = "http://code.google.com/p/photoimport/";
			about.WebsiteLabel = "http://code.google.com/p/photoimport/";
			about.License = "oh no";
			
			
			about.Authors = new string[]{"me"};
			
			//Show in the center
			about.WindowPosition = WindowPosition.Center;
			
			// Show the Dialog and pass it control
			about.Run ();
			
			// Destroy the dialog
			about.Destroy ();
		}

		/// <summary>
		/// When menu Quit is clicked 
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="System.EventArgs"/>
		/// </param>
		protected virtual void OnQuitActionActivated (object sender, System.EventArgs e)
		{
			NotBusyOrWait();
			Application.Quit ();
		}

		/// <summary>
		/// when button Settings... is clicked
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="System.EventArgs"/>
		/// </param>
		protected virtual void OnButtonSettingsClicked (object sender, System.EventArgs e)
		{
			// Create a new Settings dialog
			SettingsWindow settings = new SettingsWindow ();
			
			// Change the Dialog's properties to the appropriate values.
					
			
			// Show the Dialog and pass it control
			settings.Run ();
			
			// Destroy the dialog
			settings.Destroy ();
		}


		
		
		/// <summary>
		/// When button Download is clicked
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="System.EventArgs"/>
		/// </param>
		protected virtual void OnButtonDownloadClicked (object sender, System.EventArgs e)
		{
			if (_busy) //do not run new job if it is already running
				return ;
			
			//Save source location
			SettingFile sFile = new SettingFile();
			if (sFile.Reload ())
			{
				sFile.SourceDir = uxSourceDir.Filename;
			}
			sFile.Save();
			
			
			_busy = true;
			uxStop.Visible = true;
			
			//Start download job
			_download.RunAtBackground ();
				
		}
		private static object _lockObj = new object();

		/// <summary>
		/// When logging 
		/// </summary>
		/// <param name="pMessage">
		/// A <see cref="System.String"/>
		/// </param>
		/// <param name="pWithTimeStamp">
		/// A <see cref="System.Boolean"/>
		/// </param>
		private void HandleDownloadLogEvent (string pMessage, bool pWithTimeStamp)
		{
			lock(_lockObj)
			{
				Gtk.Application.Invoke (delegate {
					string logFile = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
					logFile = System.IO.Path.Combine(logFile, "PhotoImport.log");
					using (System.IO.StreamWriter sw = new System.IO.StreamWriter(new System.IO.FileStream(logFile, System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite)))
					{
						if (pWithTimeStamp)
								sw.Write(DateTime.Now.ToString("u") + "\t");
						sw.Write( pMessage);
						sw.Close();
					}
						
				});
			}
				
		}

		/// <summary>
		/// When progress update 
		/// </summary>
		/// <param name="pCurrent">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="pMax">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="pSpeed">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="pIsBusy">
		/// A <see cref="System.Boolean"/>
		/// </param>
		void HandleDownloadProgressUpdateEvent (int pCurrent, int pMax, long pCopied, long pTotalSize, int pSpeed, bool pIsBusy)
		{
			Gtk.Application.Invoke (delegate {
				//pSpeed == -1 means it is searching files
				if (pSpeed != -1 && pTotalSize != 0)
				{
					//actually copying
					double p = (double)pCopied / (double)pTotalSize;
					uxProgress.Fraction = p;				
					string speed = FormatBytes(pSpeed);
					uxProgress.Text = string.Format("{0:N0} of {1:N0} files...{2}/s", pCurrent, pMax, speed);
				}
				else
				{  
					uxProgress.Pulse();
					uxProgress.Text = "Estimating...";
				}
			});
		}
		
		/// <summary>
		/// Format number to human-readable form 
		/// </summary>
		/// <param name="pBytes">
		/// A <see cref="System.Int64"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.String"/>
		/// </returns>
		private string FormatBytes(long pBytes)
		{
			return (
			    pBytes >= 1073741824 ? decimal.Divide(pBytes, 1073741824).ToString("N2") + " GB" :
				pBytes >= 1048576 ? decimal.Divide(pBytes, 1048576).ToString("N2") + " MB" :
				pBytes >= 1024 ? decimal.Divide(pBytes, 1024).ToString("N2") + " KB" :
				pBytes > 0 & pBytes < 1024 ? pBytes.ToString() + "Bytes" : "0 Bytes");

		}

		/// <summary>
		/// when button stop is clicked 
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="System.EventArgs"/>
		/// </param>
		protected virtual void OnButtonCancelClicked (object sender, System.EventArgs e)
		{
			_download.Abort ();
		}
		
		

		
		
		
		
		
	}
	
}
